# 导入所需的Flask模块和其他依赖
from flask import Flask, render_template, request, redirect, url_for, flash, session
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from functools import wraps

# 创建Flask应用实例
app = Flask(__name__)
# 配置数据库URI
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.db'
# 禁用SQLAlchemy的修改跟踪功能，提高性能
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 设置密钥，用于会话和消息闪现
app.config['SECRET_KEY'] = 'your_secret_key'
# 创建SQLAlchemy实例
db = SQLAlchemy(app)

# 定义用户模型
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)  # 主键
    username = db.Column(db.String(80), unique=True, nullable=False)  # 用户名，唯一且不能为空
    password = db.Column(db.String(120), nullable=False)  # 密码，不能为空
    is_admin = db.Column(db.Boolean, default=False)  # 是否为管理员，默认为False

# 定义学生模型
class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(100), nullable=False)  # 学生姓名，不能为空
    age = db.Column(db.Integer, nullable=False)  # 学生年龄，不能为空
    grade = db.Column(db.String(50), nullable=False)  # 学生年级，不能为空

# 登录要求装饰器
def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session:  # 如果用户未登录
            flash('请先登录', 'warning')  # 显示警告消息
            return redirect(url_for('login'))  # 重定向到登录页面
        return f(*args, **kwargs)
    return decorated_function

# 管理员权限要求装饰器
def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session or not User.query.get(session['user_id']).is_admin:  # 如果用户未登录或不是管理员
            flash('需要管理员权限', 'danger')  # 显示错误消息
            return redirect(url_for('index'))  # 重定向到首页
        return f(*args, **kwargs)
    return decorated_function

# 首页路由
@app.route('/')
@login_required
def index():
    students = Student.query.all()  # 获取所有学生
    user = User.query.get(session['user_id'])  # 获取当前登录用户
    return render_template('index.html', students=students, user=user)  # 渲染首页模板

# 登录路由
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']  # 获取表单中的用户名
        password = request.form['password']  # 获取表单中的密码
        user = User.query.filter_by(username=username).first()  # 查询用户
        if user and check_password_hash(user.password, password):  # 如果用户存在且密码正确
            session['user_id'] = user.id  # 将用户ID存入会话
            flash('登录成功!', 'success')  # 显示成功消息
            return redirect(url_for('index'))  # 重定向到首页
        flash('用户名或密码错误', 'danger')  # 显示错误消息
    return render_template('login.html')  # 渲染登录页面模板

# 注册路由
@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']  # 获取表单中的用户名
        password = request.form['password']  # 获取表单中的密码
        existing_user = User.query.filter_by(username=username).first()  # 检查用户名是否已存在
        if existing_user:
            flash('用户名已存在', 'danger')  # 显示错误消息
        else:
            hashed_password = generate_password_hash(password)  # 对密码进行哈希处理
            new_user = User(username=username, password=hashed_password)  # 创建新用户
            db.session.add(new_user)  # 添加新用户到数据库会话
            db.session.commit()  # 提交数据库更改
            flash('注册成功,请登录', 'success')  # 显示成功消息
            return redirect(url_for('login'))  # 重定向到登录页面
    return render_template('register.html')  # 渲染注册页面模板

# 注销路由
@app.route('/logout')
def logout():
    session.pop('user_id', None)  # 从会话中移除用户ID
    flash('已注销', 'info')  # 显示信息消息
    return redirect(url_for('login'))  # 重定向到登录页面

# 添加学生路由
@app.route('/add', methods=['GET', 'POST'])
@login_required
@admin_required
def add_student():
    if request.method == 'POST':
        name = request.form['name']  # 获取表单中的学生姓名
        age = request.form['age']  # 获取表单中的学生年龄
        grade = request.form['grade']  # 获取表单中的学生年级
        
        new_student = Student(name=name, age=age, grade=grade)  # 创建新学生对象
        db.session.add(new_student)  # 添加新学生到数据库会话
        db.session.commit()  # 提交数据库更改
        
        flash('学生添加成功!', 'success')  # 显示成功消息
        return redirect(url_for('index'))  # 重定向到首页
    return render_template('add_student.html')  # 渲染添加学生页面模板

# 编辑学生路由
@app.route('/edit/<int:id>', methods=['GET', 'POST'])
@login_required
@admin_required
def edit_student(id):
    student = Student.query.get_or_404(id)  # 获取指定ID的学生，如果不存在则返回404错误
    if request.method == 'POST':
        student.name = request.form['name']  # 更新学生姓名
        student.age = request.form['age']  # 更新学生年龄
        student.grade = request.form['grade']  # 更新学生年级
        
        db.session.commit()  # 提交数据库更改
        flash('学生信息更新成功!', 'success')  # 显示成功消息
        return redirect(url_for('index'))  # 重定向到首页
    return render_template('edit_student.html', student=student)  # 渲染编辑学生页面模板

# 删除学生路由
@app.route('/delete/<int:id>')
@login_required
@admin_required
def delete_student(id):
    student = Student.query.get_or_404(id)  # 获取指定ID的学生，如果不存在则返回404错误
    db.session.delete(student)  # 从数据库会话中删除学生
    db.session.commit()  # 提交数据库更改
    flash('学生删除成功!', 'success')  # 显示成功消息
    return redirect(url_for('index'))  # 重定向到首页

# 搜索学生路由
@app.route('/search')
@login_required
def search_student():
    query = request.args.get('query')  # 获取搜索查询参数
    students = Student.query.filter(Student.name.contains(query) | 
                                    Student.grade.contains(query)).all()  # 搜索匹配的学生
    user = User.query.get(session['user_id'])  # 获取当前登录用户
    
    if not students:
        flash(f'没有找到匹配 "{query}" 的学生', 'info')  # 如果没有找到匹配的学生，显示信息消息
    
    return render_template('index.html', students=students, user=user, search_query=query)  # 渲染搜索结果页面

# 主程序入口
if __name__ == '__main__':
    with app.app_context():
        db.create_all()  # 创建所有数据库表
        # 创建管理员账户（如果不存在）
        admin = User.query.filter_by(username='admin').first()
        if not admin:
            admin = User(username='admin', password=generate_password_hash('admin'), is_admin=True)
            db.session.add(admin)
            db.session.commit()
    app.run(debug=True)  # 以调试模式运行应用